package flexo.state;

import java.util.HashMap;

import flexo.common.LogMsgType;

public class StateSystem extends flexo.common.System
{
	public static final String ID = "state";
	
	protected boolean firstStart;
	protected HashMap<String, Object> stateList;
	protected State currentState;
	
	public StateSystem(String[] stateList)
	{
		this();
		
		for (String s : stateList)
		{
			add(s);
		}
	}
	
	public StateSystem(String state)
	{
		this();
		add(state);
	}
	
	public StateSystem()
	{
		super(ID,flexo.common.System.UPDATE_STANDARD);
		stateList = new HashMap<String, Object>();
		firstStart = true;
	}
	
	@SuppressWarnings("unchecked")
	/**
	 * Adds a state to the engine. If it's the first time you call this function, 
	 * the state is marked as the initial state.
	 */
	public void add(String name)
	{
		State state = null;
		
		// Create an instance of class 'name'
		try
		{
			// This generates a warning because compiler can't check it in compile time
			Class<State> clss = (Class<State>) Class.forName(name);
			state = clss.newInstance();
		}
		catch (ClassNotFoundException e)
		{
			flexo.Kernel.log("flexo.state.StateSystem", "State '" + name + "' not found", LogMsgType.ERROR);
			flexo.Kernel.error();
		}
		catch (InstantiationException e)
		{
			flexo.Kernel.log("flexo.state.StateSystem", "Error creating '" + name + "' state", LogMsgType.ERROR);
			flexo.Kernel.error();
		}
		catch (IllegalAccessException e)
		{
			flexo.Kernel.log("flexo.state.StateSystem", "Error creating '" + name + "' state", LogMsgType.ERROR);
			flexo.Kernel.error();
		}
		catch (Exception e)
		{
			flexo.Kernel.log("flexo.state.StateSystem", "Error creating '" + name + "' state", LogMsgType.ERROR);
			flexo.Kernel.error();
		}
		
		// Put the instance inside the HashMap
		if (get(name) != null)
		{
			flexo.Kernel.log("flexo.state.StateSystem", "The state '" + name + "' already exists!", LogMsgType.ERROR);
			flexo.Kernel.error();
		}
		else
		{
			add(name, state);
			
			if (currentState == null)
			{
				currentState = state;				
			}
		}
	}
	
	protected Object get(String stateName)
	{
		return stateList.get(stateName);
	}
	
	protected void add(String stateName, State state)
	{
		stateList.put(stateName, state);
	}
	
	@Override
	public void update()
	{
		if (currentState == null)
		{
			flexo.Kernel.log("flexo.state.Manater", "An initial state must be specified!", LogMsgType.ERROR);
			flexo.Kernel.error();
		}
		
		if (firstStart)
		{
			firstStart = false;
			currentState.init();
		}
		
		currentState.update();
		if (currentState.isExit())
		{
			currentState.cleanUp();
			currentState = (State)get(currentState.getNextState());
			// No more states, melt is stopped
			if (currentState == null)
			{
				flexo.Kernel.release();
			}
			currentState.init();
		}
	}
}
